package org.airlink.persistence.query {
	import flash.data.SQLResult;
	import flash.data.SQLStatement;
	import flash.errors.IllegalOperationError;
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	import flash.utils.getQualifiedClassName;
	
	import flex.persistence.EntityManager;
	import flex.persistence.EntityTransaction;
	import flex.persistence.FlushModeType;
	import flex.persistence.Query;
	import flex.persistence.exceptions.IllegalArgumentException;
	import flex.persistence.exceptions.NoResultException;
	import flex.persistence.exceptions.NonUniqueResultException;
	
	import mx.utils.ObjectUtil;
	import mx.utils.StringUtil;
	
	import org.airlink.persistence.Entity;
	import org.airlink.persistence.EntityIntrospector;
	import org.airlink.persistence.EntityManagerImpl;
	import org.airlink.persistence.associations.Association;
	import org.airlink.persistence.associations.BasicField;
	import org.airlink.persistence.associations.ManyToManyAssociation;
	import org.airlink.persistence.associations.ManyToOneAssociation;
	import org.airlink.persistence.associations.OneToManyAssociation;
	import org.airlink.persistence.associations.OneToOneAssociation;
	
	public class AbstractQuery implements Query {
		protected var resultClass:Class;
		protected var isSimple:Boolean = false;
		protected var query:String;
		protected var entityManager:EntityManagerImpl;
		protected var transaction:EntityTransaction;
		protected var parameters:Dictionary;
		
		public function AbstractQuery(query:String, entityManager:EntityManagerImpl, transaction:EntityTransaction) {
			if(getQualifiedClassName(this) == getQualifiedClassName(AbstractQuery))
				throw new Error("AbstractQuery is Abstract");
			this.query = query;
			this.entityManager = entityManager;
			if(!transaction) transaction = entityManager.getTransaction();
			this.transaction = transaction;
			this.parameters = new Dictionary();
		}

		public function executeUpdate():int {
			throw new IllegalOperationError("AbstractQuery is an abstract Class.");
		}
		
		public function getResultList():Array {
			throw new IllegalOperationError("AbstractQuery is an abstract Class.");
		}
		
		public function getSingleResult():Object {
			throw new IllegalOperationError("AbstractQuery is an abstract Class.");
		}
		
		public function setFirstResult(startPosition:int):Query {
			throw new IllegalOperationError("AbstractQuery is an abstract Class.");
		}
		
		public function setFlushMode(flushMode:FlushModeType):Query {
			throw new IllegalOperationError("AbstractQuery is an abstract Class.");
		}
		
		public function setHint(hintName:String, value:Object):Query {
			throw new IllegalOperationError("AbstractQuery is an abstract Class.");
		}
		
		public function setMaxResults(maxResult:int):Query {
			throw new IllegalOperationError("AbstractQuery is an abstract Class.");
		}
		
		public function setParameterByIndex(position:int, value:Object):Query {			
			this.parameters["?"+position] = value;	
			return this;
		}

		public function setParameterByName(name:String, value:Object):Query {	
			this.parameters[":"+name] = value;	
			return this;
		}

		protected function transformResult(object:Object):* {
			var result:*;
			if(isSimple) {
				for(var key:String in object) {
					result = object[key];
					if(!(result is resultClass)) {
						if(resultClass == Date) {
							var timestamp:Number = result;
							result = new Date();
							result.time = timestamp;
						} else {
							result = resultClass(result);
						}
					}
					break;
				}
			} else {			
				var entity:Entity = entityManager.introspector.loadMetadata(resultClass);
				var id:Object = object[entity.idField.columnName];
				if(!id) throw new IllegalArgumentException("Syntax error parsing the query ["+query+"], expected token ["+entity.idField.columnName+"]");
				result = entityManager.find(resultClass, id, transaction); 
			}
			return result;
		}
		
		public function getSql():String {
			return this.query;
		}
	}
}